home *** CD-ROM | disk | FTP | other *** search
/ The Datafile PD-CD 1 Issue 2 / PDCD-1 - Issue 02.iso / _utilities / utilities / 001 / fue / c / bind < prev    next >
Text File  |  1991-04-08  |  33KB  |  1,079 lines

  1. /*      This file is for functions having to do with key bindings,
  2.         descriptions, help commands and startup file.
  3.  
  4.         written 11-feb-86 by Daniel Lawrence
  5.                                                                 */
  6.  
  7. #include        <stdio.h>
  8. #include        "estruct.h"
  9. #include        "etype.h"
  10. #include        "edef.h"
  11. #include        "elang.h"
  12. #include        "epath.h"
  13.  
  14. PASCAL NEAR betawarning(f, n)   /* warn them !!!!
  15.                    bring up a fake buffer and read the beta warning file
  16.                    into it with view mode                       */
  17. {
  18.         register BUFFER *bp;    /* buffer pointer to help */
  19.         char *fname;            /* file name of help file */
  20.  
  21.         /* first check if we are already here */
  22.         bp = bfind("emacs.inf", FALSE, BFINVS);
  23.  
  24.         if (bp == NULL) {
  25. #if SHARED
  26.                 strcpy(tname, "emacs.inf");
  27.                 fname = flook(tname, FALSE);
  28. #else       
  29.                 fname = flook("emacs.inf", FALSE);
  30. #endif
  31.                 if (fname == NULL) {
  32.                         mlwrite(TEXT12);
  33. /*                              "[Help file is not online]" */
  34.                         return(FALSE);
  35.                 }
  36.         }
  37.  
  38.         /* split the current window to make room for the help stuff */
  39.         if (splitwind(FALSE, 1) == FALSE)
  40.                         return(FALSE);
  41.  
  42.         if (bp == NULL) {
  43.                 /* and read the stuff in */
  44.                 if (getfile(fname, FALSE) == FALSE)
  45.                         return(FALSE);
  46.         } else
  47.                 swbuffer(bp);
  48.  
  49.         /* make this window in VIEW mode, update all mode lines */
  50.         curwp->w_bufp->b_mode |= MDVIEW;
  51.         curwp->w_bufp->b_flag |= BFINVS;
  52.         upmode();
  53.         return(TRUE);
  54. }
  55.  
  56.  
  57. PASCAL NEAR help(f, n)  /* give me some help!!!!
  58.                    bring up a fake buffer and read the help file
  59.                    into it with view mode                       */
  60. {
  61.         register BUFFER *bp;    /* buffer pointer to help */
  62.         char *fname;            /* file name of help file */
  63.  
  64.         /* first check if we are already here */
  65.         bp = bfind("emacs.hlp", FALSE, BFINVS);
  66.  
  67.         if (bp == NULL) {
  68. #if SHARED
  69.                 strcpy(tname, pathname[1]);
  70.                 fname = flook(tname, FALSE);
  71. #else       
  72.                 fname = flook(pathname[1], FALSE);
  73. #endif
  74.                 if (fname == NULL) {
  75.                         mlwrite(TEXT12);
  76. /*                              "[Help file is not online]" */
  77.                         return(FALSE);
  78.                 }
  79.         }
  80.  
  81.         /* split the current window to make room for the help stuff */
  82.         if (splitwind(FALSE, 1) == FALSE)
  83.                         return(FALSE);
  84.  
  85.         if (bp == NULL) {
  86.                 /* and read the stuff in */
  87.                 if (getfile(fname, FALSE) == FALSE)
  88.                         return(FALSE);
  89.         } else
  90.                 swbuffer(bp);
  91.  
  92.         /* make this window in VIEW mode, update all mode lines */
  93.         curwp->w_bufp->b_mode |= MDVIEW;
  94.         curwp->w_bufp->b_flag |= BFINVS;
  95.         upmode();
  96.         return(TRUE);
  97. }
  98.  
  99. PASCAL NEAR deskey(f, n)        /* describe the command for a certain key */
  100.  
  101. {
  102.         register int c;         /* key to describe */
  103.         register char *ptr;     /* string pointer to scan output strings */
  104.         char outseq[NSTRING];   /* output buffer for command sequence */
  105.  
  106.         /* prompt the user to type us a key to describe */
  107.         mlwrite(TEXT13);
  108. /*              ": describe-key " */
  109.  
  110.         /* get the command sequence to describe
  111.            change it to something we can print as well */
  112.         cmdstr(c = getckey(FALSE), &outseq[0]);
  113.  
  114.         /* and dump it out */
  115.         ostring(outseq);
  116.         ostring(" ");
  117.  
  118.         /* find the right ->function */
  119.         if ((ptr = getfname(getbind(c))) == NULL)
  120.                 ptr = "Not Bound";
  121.  
  122.         /* output the command sequence */
  123.         ostring(ptr);
  124. }
  125.  
  126. /* bindtokey:   add a new key to the key binding table          */
  127.  
  128. PASCAL NEAR bindtokey(f, n)
  129.  
  130. int f, n;       /* command arguments [IGNORED] */
  131.  
  132. {
  133.         register unsigned int c;/* command key to bind */
  134.         register int (PASCAL NEAR *kfunc)();/* ptr to the requested function to bind to */
  135.         register KEYTAB *ktp;   /* pointer into the command table */
  136.         register int found;     /* matched command flag */
  137.         char outseq[80];        /* output buffer for keystroke sequence */
  138.  
  139.         /* prompt the user to type in a key to bind */
  140.         /* get the function name to bind it to */
  141.         kfunc = getname(TEXT15);
  142. /*                      ": bind-to-key " */
  143.         if (kfunc == NULL) {
  144.                 mlwrite(TEXT16);
  145. /*                      "[No such function]" */
  146.                 return(FALSE);
  147.         }
  148.         ostring(" ");
  149.         TTflush();
  150.  
  151.         /* get the command sequence to bind */
  152.         c = getckey((kfunc == meta) || (kfunc == cex) ||
  153.                     (kfunc == unarg) || (kfunc == ctrlg));
  154.  
  155.         /* change it to something we can print as well */
  156.         cmdstr(c, &outseq[0]);
  157.  
  158.         /* and dump it out */
  159.         ostring(outseq);
  160.  
  161.         /* if the function is a unique prefix key */
  162.         if (kfunc == unarg || kfunc == ctrlg) {
  163.  
  164.                 /* search for an existing binding for the prefix key */
  165.                 ktp = &keytab[0];
  166.                 while (ktp->k_ptr.fp != NULL) {
  167.                         if (ktp->k_ptr.fp == kfunc)
  168.                                 unbindchar(ktp->k_code);
  169.                         ++ktp;
  170.                 }
  171.  
  172.                 /* reset the appropriate global prefix variable */
  173.                 if (kfunc == unarg)
  174.                         reptc = c;
  175.                 if (kfunc == ctrlg)
  176.                         abortc = c;
  177.         }
  178.  
  179.         /* search the table to see if it exists */
  180.         ktp = &keytab[0];
  181.         found = FALSE;
  182.         while (ktp->k_ptr.fp != NULL) {
  183.                 if (ktp->k_code == c) {
  184.                         found = TRUE;
  185.                         break;
  186.                 }
  187.                 ++ktp;
  188.         }
  189.  
  190.         if (found) {    /* it exists, just change it then */
  191.                 ktp->k_ptr.fp = kfunc;
  192.                 ktp->k_type = BINDFNC;
  193.         } else {        /* otherwise we need to add it to the end */
  194.                 /* if we run out of binding room, bitch */
  195.                 if (ktp >= &keytab[NBINDS]) {
  196.                         mlwrite(TEXT17);
  197. /*                              "Binding table FULL!" */
  198.                         return(FALSE);
  199.                 }
  200.  
  201.                 ktp->k_code = c;        /* add keycode */
  202.                 ktp->k_ptr.fp = kfunc;  /* and the function pointer */
  203.                 ktp->k_type = BINDFNC;  /* and the binding type */
  204.                 ++ktp;                  /* and make sure the next is null */
  205.                 ktp->k_code = 0;
  206.                 ktp->k_type = BINDNUL;
  207.                 ktp->k_ptr.fp = NULL;
  208.         }
  209.  
  210.         /* if we have rebound the meta key, make the
  211.            search terminator follow it                  */
  212.         if (kfunc == meta)
  213.                 sterm = c;
  214.  
  215.         return(TRUE);
  216. }
  217.  
  218. /* macrotokey:  Bind a key to a macro in the key binding table */
  219.  
  220. PASCAL NEAR macrotokey(f, n)
  221.  
  222. int f, n;       /* command arguments [IGNORED] */
  223.  
  224. {
  225.         register unsigned int c;/* command key to bind */
  226.         register BUFFER *kmacro;/* ptr to buffer of macro to bind to key */
  227.         register KEYTAB *ktp;   /* pointer into the command table */
  228.         register int found;     /* matched command flag */
  229.         register int status;    /* error return */
  230.         char outseq[80];        /* output buffer for keystroke sequence */
  231.         char bufn[NBUFN];       /* buffer to hold macro name */
  232.  
  233.         /* get the buffer name to use */
  234.         if ((status=mlreply(TEXT215, &bufn[1], NBUFN-2)) != TRUE)
  235. /*              ": macro-to-key " */
  236.                 return(status);
  237.  
  238.         /* build the responce string for later */
  239.         strcpy(outseq, TEXT215);
  240. /*                 ": macro-to-key " */
  241.         strcat(outseq, &bufn[1]);
  242.  
  243.         /* translate it to a buffer pointer */
  244.         bufn[0] = '[';
  245.         strcat(bufn, "]");
  246.         if ((kmacro=bfind(bufn, FALSE, 0)) == NULL) {
  247.                 mlwrite(TEXT130);
  248. /*              "Macro not defined"*/
  249.                 return(FALSE);
  250.         }
  251.  
  252.         strcat(outseq, " ");
  253.         mlwrite(outseq);
  254.  
  255.         /* get the command sequence to bind */
  256.         c = getckey(FALSE);
  257.  
  258.         /* change it to something we can print as well */
  259.         cmdstr(c, &outseq[0]);
  260.  
  261.         /* and dump it out */
  262.         ostring(outseq);
  263.  
  264.         /* search the table to see if it exists */
  265.         ktp = &keytab[0];
  266.         found = FALSE;
  267.         while (ktp->k_type != BINDNUL) {
  268.                 if (ktp->k_code == c) {
  269.                         found = TRUE;
  270.                         break;
  271.                 }
  272.                 ++ktp;
  273.         }
  274.  
  275.         if (found) {    /* it exists, just change it then */
  276.                 ktp->k_ptr.buf = kmacro;
  277.                 ktp->k_type = BINDBUF;
  278.         } else {        /* otherwise we need to add it to the end */
  279.                 /* if we run out of binding room, bitch */
  280.                 if (ktp >= &keytab[NBINDS]) {
  281.                         mlwrite(TEXT17);
  282. /*                              "Binding table FULL!" */
  283.                         return(FALSE);
  284.                 }
  285.  
  286.                 ktp->k_code = c;        /* add keycode */
  287.                 ktp->k_ptr.buf = kmacro;        /* and the function pointer */
  288.                 ktp->k_type = BINDBUF;  /* and the binding type */
  289.                 ++ktp;                  /* and make sure the next is null */
  290.                 ktp->k_code = 0;
  291.                 ktp->k_type = BINDNUL;
  292.                 ktp->k_ptr.fp = NULL;
  293.         }
  294.  
  295.         return(TRUE);
  296. }
  297.  
  298. /* unbindkey:   delete a key from the key binding table */
  299.  
  300. PASCAL NEAR unbindkey(f, n)
  301.  
  302. int f, n;       /* command arguments [IGNORED] */
  303.  
  304. {
  305.         register int c;         /* command key to unbind */
  306.         char outseq[80];        /* output buffer for keystroke sequence */
  307.  
  308.         /* prompt the user to type in a key to unbind */
  309.         mlwrite(TEXT18);
  310. /*              ": unbind-key " */
  311.  
  312.         /* get the command sequence to unbind */
  313.         c = getckey(FALSE);             /* get a command sequence */
  314.  
  315.         /* change it to something we can print as well */
  316.         cmdstr(c, &outseq[0]);
  317.  
  318.         /* and dump it out */
  319.         ostring(outseq);
  320.  
  321.         /* if it isn't bound, bitch */
  322.         if (unbindchar(c) == FALSE) {
  323.                 mlwrite(TEXT19);
  324. /*                      "[Key not bound]" */
  325.                 return(FALSE);
  326.         }
  327.         return(TRUE);
  328. }
  329.  
  330. PASCAL NEAR unbindchar(c)
  331.  
  332. int c;          /* command key to unbind */
  333.  
  334. {
  335.         register KEYTAB *ktp;   /* pointer into the command table */
  336.         register KEYTAB *sktp;  /* saved pointer into the command table */
  337.         register int found;     /* matched command flag */
  338.  
  339.         /* search the table to see if the key exists */
  340.         ktp = &keytab[0];
  341.         found = FALSE;
  342.         while (ktp->k_type != BINDNUL) {
  343.                 if (ktp->k_code == c) {
  344.                         found = TRUE;
  345.                         break;
  346.                 }
  347.                 ++ktp;
  348.         }
  349.  
  350.         /* if it isn't bound, bitch */
  351.         if (!found)
  352.                 return(FALSE);
  353.  
  354.         /* save the pointer and scan to the end of the table */
  355.         sktp = ktp;
  356.         while (ktp->k_ptr.fp != NULL)
  357.                 ++ktp;
  358.         --ktp;          /* backup to the last legit entry */
  359.  
  360.         /* copy the last entry to the current one */
  361.         sktp->k_code = ktp->k_code;
  362.         sktp->k_type = ktp->k_type;
  363.         sktp->k_ptr.fp   = ktp->k_ptr.fp;
  364.  
  365.         /* null out the last one */
  366.         ktp->k_code = 0;
  367.         ktp->k_type = BINDNUL;
  368.         ktp->k_ptr.fp = NULL;
  369.         return(TRUE);
  370. }
  371.  
  372. /* Describe bindings:
  373.  
  374.            bring up a fake buffer and list the key bindings
  375.            into it with view mode
  376. */
  377.  
  378. PASCAL NEAR desbind(f, n)
  379.  
  380. #if     APROP
  381. {
  382.         return(buildlist(TRUE, ""));
  383. }
  384.  
  385. PASCAL NEAR apro(f, n)  /* Apropos (List functions that match a substring) */
  386.  
  387. {
  388.         char mstring[NSTRING];  /* string to match cmd names to */
  389.         int status;             /* status return */
  390.  
  391.         status = mlreply(TEXT20, mstring, NSTRING - 1);
  392. /*                       "Apropos string: " */
  393.         if (status != TRUE)
  394.                 return(status);
  395.  
  396.         return(buildlist(FALSE, mstring));
  397. }
  398.  
  399. PASCAL NEAR buildlist(type, mstring)  /* build a binding list (limited or full) */
  400.  
  401. int type;       /* true = full list,   false = partial list */
  402. char *mstring;  /* match string if a partial list */
  403.  
  404. #endif
  405. {
  406.         register WINDOW *wp;    /* scanning pointer to windows */
  407.         register KEYTAB *ktp;   /* pointer into the command table */
  408.         register NBIND *nptr;   /* pointer into the name binding table */
  409.         register BUFFER *bp;    /* buffer to put binding list into */
  410.         int cpos;               /* current position to use in outseq */
  411.         int cmark;              /* current mark */
  412.         char outseq[80];        /* output buffer for keystroke sequence */
  413.  
  414.         /* split the current window to make room for the binding list */
  415.         if (splitwind(FALSE, 1) == FALSE)
  416.                         return(FALSE);
  417.  
  418.         /* and get a buffer for it */
  419.         bp = bfind(TEXT21, TRUE, 0);
  420. /*                 "Binding list" */
  421.         if (bp == NULL || bclear(bp) == FALSE) {
  422.                 mlwrite(TEXT22);
  423. /*                      "Can not display binding list" */
  424.                 return(FALSE);
  425.         }
  426.  
  427.         /* let us know this is in progress */
  428.         mlwrite(TEXT23);
  429. /*              "[Building binding list]" */
  430.  
  431.         /* disconect the current buffer */
  432.         if (--curbp->b_nwnd == 0) {             /* Last use.            */
  433.                 curbp->b_dotp  = curwp->w_dotp;
  434.                 curbp->b_doto  = curwp->w_doto;
  435.                 for (cmark = 0; cmark < NMARKS; cmark++) {
  436.                         curbp->b_markp[cmark] = curwp->w_markp[cmark];
  437.                         curbp->b_marko[cmark] = curwp->w_marko[cmark];
  438.                 }
  439.                 curbp->b_fcol  = curwp->w_fcol;
  440.         }
  441.  
  442.         /* connect the current window to this buffer */
  443.         curbp = bp;     /* make this buffer current in current window */
  444.         bp->b_mode = 0;         /* no modes active in binding list */
  445.         bp->b_nwnd++;           /* mark us as more in use */
  446.         wp = curwp;
  447.         wp->w_bufp = bp;
  448.         wp->w_linep = bp->b_linep;
  449.         wp->w_flag = WFHARD|WFFORCE;
  450.         wp->w_dotp = bp->b_dotp;
  451.         wp->w_doto = bp->b_doto;
  452.         for (cmark = 0; cmark < NMARKS; cmark++) {
  453.                 wp->w_markp[cmark] = NULL;
  454.                 wp->w_marko[cmark] = 0;
  455.         }
  456.  
  457.         /* build the contents of this window, inserting it line by line */
  458.         nptr = &names[0];
  459.         while (nptr->n_func != NULL) {
  460.  
  461.                 /* add in the command name */
  462.                 strcpy(outseq, nptr->n_name);
  463.                 cpos = strlen(outseq);
  464.  
  465. #if     APROP
  466.                 /* if we are executing an apropos command..... */
  467.                 if (type == FALSE &&
  468.                     /* and current string doesn't include the search string */
  469.                     strinc(outseq, mstring) == FALSE)
  470.                         goto fail;
  471. #endif
  472.                 /* search down any keys bound to this */
  473.                 ktp = &keytab[0];
  474.                 while (ktp->k_type != BINDNUL) {
  475.                         if (ktp->k_type == BINDFNC &&
  476.                             ktp->k_ptr.fp == nptr->n_func) {
  477.                                 /* padd out some spaces */
  478.                                 while (cpos < 25)
  479.                                         outseq[cpos++] = ' ';
  480.  
  481.                                 /* add in the command sequence */
  482.                                 cmdstr(ktp->k_code, &outseq[cpos]);
  483.                                 strcat(outseq, "\r");
  484.  
  485.                                 /* and add it as a line into the buffer */
  486.                                 if (linstr(outseq) != TRUE)
  487.                                         return(FALSE);
  488.  
  489.                                 cpos = 0;       /* and clear the line */
  490.                         }
  491.                         ++ktp;
  492.                 }
  493.  
  494.                 /* if no key was bound, we need to dump it anyway */
  495.                 if (cpos > 0) {
  496.                         outseq[cpos++] = '\r';
  497.                         outseq[cpos] = 0;
  498.                         if (linstr(outseq) != TRUE)
  499.                                 return(FALSE);
  500.                 }
  501.  
  502. fail:           /* and on to the next name */
  503.                 ++nptr;
  504.         }
  505.  
  506.         /* add a blank line between the key and macro lists */
  507.         lnewline();
  508.  
  509.         /* scan all buffers looking for macroes and their bindings */
  510.         bp = bheadp;
  511.         while (bp) {
  512.  
  513.                 /* is this buffer a macro? */
  514.                 if (bp->b_bname[0] != '[')
  515.                         goto bfail;
  516.  
  517.                 /* add in the command name */
  518.                 strcpy(outseq, bp->b_bname);
  519.                 cpos = strlen(outseq);
  520.  
  521. #if     APROP
  522.                 /* if we are executing an apropos command..... */
  523.                 if (type == FALSE &&
  524.                     /* and current string doesn't include the search string */
  525.                     strinc(outseq, mstring) == FALSE)
  526.                         goto bfail;
  527. #endif
  528.                 /* search down any keys bound to this macro */
  529.                 ktp = &keytab[0];
  530.                 while (ktp->k_ptr.fp != NULL) {
  531.                         if (ktp->k_type == BINDBUF &&
  532.                             ktp->k_ptr.buf == bp) {
  533.                                 /* padd out some spaces */
  534.                                 while (cpos < 25)
  535.                                         outseq[cpos++] = ' ';
  536.  
  537.                                 /* add in the command sequence */
  538.                                 cmdstr(ktp->k_code, &outseq[cpos]);
  539.                                 strcat(outseq, "\r");
  540.  
  541.                                 /* and add it as a line into the buffer */
  542.                                 if (linstr(outseq) != TRUE)
  543.                                         return(FALSE);
  544.  
  545.                                 cpos = 0;       /* and clear the line */
  546.                         }
  547.                         ++ktp;
  548.                 }
  549.  
  550.                 /* if no key was bound, we need to dump it anyway */
  551.                 if (cpos > 0) {
  552.                         outseq[cpos++] = '\r';
  553.                         outseq[cpos] = 0;
  554.                         if (linstr(outseq) != TRUE)
  555.                                 return(FALSE);
  556.                 }
  557.  
  558. bfail:          /* and on to the next buffer */
  559.                 bp = bp->b_bufp;
  560.         }
  561.  
  562.         curwp->w_bufp->b_mode |= MDVIEW;/* put this buffer view mode */
  563.         curbp->b_flag &= ~BFCHG;        /* don't flag this as a change */
  564.         wp->w_dotp = lforw(curbp->b_linep);/* back to the beginning */
  565.         wp->w_doto = 0;
  566.         upmode();
  567.         mlwrite("");    /* clear the mode line */
  568.         return(TRUE);
  569. }
  570.  
  571. #if     APROP
  572. PASCAL NEAR strinc(source, sub) /* does source include sub? */
  573.  
  574. char *source;   /* string to search in */
  575. char *sub;      /* substring to look for */
  576.  
  577. {
  578.         char *sp;       /* ptr into source */
  579.         char *nxtsp;    /* next ptr into source */
  580.         char *tp;       /* ptr into substring */
  581.  
  582.         /* for each character in the source string */
  583.         sp = source;
  584.         while (*sp) {
  585.                 tp = sub;
  586.                 nxtsp = sp;
  587.  
  588.                 /* is the substring here? */
  589.                 while (*tp) {
  590.                         if (*nxtsp++ != *tp)
  591.                                 break;
  592.                         else
  593.                                 tp++;
  594.                 }
  595.  
  596.                 /* yes, return a success */
  597.                 if (*tp == 0)
  598.                         return(TRUE);
  599.  
  600.                 /* no, onward */
  601.                 sp++;
  602.         }
  603.         return(FALSE);
  604. }
  605. #endif
  606.  
  607. /* get a command key sequence from the keyboard */
  608.  
  609. unsigned int PASCAL NEAR getckey(mflag)
  610.  
  611. int mflag;      /* going for a meta sequence? */
  612.  
  613. {
  614.         register unsigned int c;        /* character fetched */
  615.         char tok[NSTRING];              /* command incoming */
  616.  
  617.         /* check to see if we are executing a command line */
  618.         if (clexec) {
  619.                 macarg(tok);    /* get the next token */
  620.                 return(stock(tok));
  621.         }
  622.  
  623.         /* or the normal way */
  624.         if (mflag)
  625.                 c = getkey();
  626.         else
  627.                 c = getcmd();
  628.         return(c);
  629. }
  630.  
  631. /* execute the startup file */
  632.  
  633. PASCAL NEAR startup(sfname)
  634.  
  635. char *sfname;   /* name of startup file (null if default) */
  636.  
  637. {
  638.         char *fname;    /* resulting file name to execute */
  639.  
  640.         /* look up the startup file */
  641.         if (*sfname != 0)
  642.                 fname = flook(sfname, TRUE);
  643.         else
  644. #if SHARED
  645.         {
  646.                 strcpy(tname, pathname[0]);
  647.                 fname = flook(tname, TRUE);
  648.         }
  649. #else
  650.                 fname = flook(pathname[0], TRUE);
  651. #endif
  652.  
  653.         /* if it isn't around, don't sweat it */
  654.         if (fname == NULL)
  655.                 return(TRUE);
  656.  
  657.         /* otherwise, execute the sucker */
  658.         return(dofile(fname));
  659. }
  660.  
  661. /*      Look up the existance of a file along the normal or PATH
  662.         environment variable. Look first in the HOME directory if
  663.         asked and possible
  664. */
  665.  
  666. char *PASCAL NEAR flook(fname, hflag)
  667.  
  668. char *fname;    /* base file name to search for */
  669. int hflag;      /* Look in the HOME environment variable first? */
  670.  
  671. {
  672.         register char *home;    /* path to home directory */
  673.         register char *path;    /* environmental PATH variable */
  674.         register char *sp;      /* pointer into path spec */
  675.         register int i;         /* index */
  676.         static char fspec[NFILEN];      /* full path spec to search */
  677.         char *getenv();
  678.  
  679.         /* if we have an absolute path.. check only there! */
  680.         sp = fname;
  681.         while (*sp) {
  682.                 if (*sp == ':' || *sp == DIRSEPCHAR) {
  683.                         if (ffropen(fname) == FIOSUC) {
  684.                                 ffclose();
  685.                                 return(fname);
  686.                         } else
  687.                                 return(NULL);
  688.                 }
  689.                 ++sp;
  690.         }
  691.  
  692. #if     ENVFUNC
  693.  
  694.         if (hflag) {
  695. #if WMCS
  696.                 home = getenv("SYS$HOME");
  697. #else
  698.                 home = getenv("HOME");
  699. #endif
  700.                 if (home != NULL) {
  701.                         /* build home dir file spec */
  702.                         strcpy(fspec, home);
  703. #if WMCS
  704.                         strcat(fspec,fname);
  705. #else
  706.                         strcat(fspec, "/");
  707.                         strcat(fspec, fname);
  708. #endif
  709.  
  710.                         /* and try it out */
  711.                         if (ffropen(fspec) == FIOSUC) {
  712.                                 ffclose();
  713.                                 return(fspec);
  714.                         }
  715.                 }
  716.         }
  717. #endif
  718.  
  719.         /* always try the current directory first */
  720.         if (ffropen(fname) == FIOSUC) {
  721.                 ffclose();
  722.                 return(fname);
  723.         }
  724.  
  725. #if     ENVFUNC
  726.         /* get the PATH variable */
  727. #if WMCS
  728.         path = getenv("OPT$PATH");
  729. #else
  730.         path = getenv("PATH");
  731. #endif
  732.         if (path != NULL)
  733.                 while (*path) {
  734.  
  735.                         /* build next possible file spec */
  736.                         sp = fspec;
  737. #if     ST520 & MWC
  738.                         while (*path && (*path != PATHCHR) && (*path != ','))
  739. #else
  740.                         while (*path && (*path != PATHCHR))
  741. #endif
  742.                                 *sp++ = *path++;
  743.  
  744.                         /* add a terminating dir separator if we need it */
  745.                         if (*(sp-1) != DIRSEPCHAR)
  746.                                 *sp++ = DIRSEPCHAR;
  747.                         *sp = 0;
  748.                         strcat(fspec, fname);
  749.  
  750.                         /* and try it out */
  751.                         if (ffropen(fspec) == FIOSUC) {
  752.                                 ffclose();
  753.                                 return(fspec);
  754.                         }
  755.  
  756. #if     ST520 & MWC
  757.                         if ((*path == PATHCHR) || (*path == ','))
  758. #else
  759.                         if (*path == PATHCHR)
  760. #endif
  761.                                 ++path;
  762.                 }
  763. #endif
  764.  
  765.         /* look it up via the old table method */
  766.         for (i=2; i < NPNAMES; i++) {
  767.                 strcpy(fspec, pathname[i]);
  768.                 strcat(fspec, fname);
  769.  
  770.                 /* and try it out */
  771.                 if (ffropen(fspec) == FIOSUC) {
  772.                         ffclose();
  773.                         return(fspec);
  774.                 }
  775.         }
  776.  
  777.         return(NULL);   /* no such luck */
  778. }
  779.  
  780. PASCAL NEAR cmdstr(c, seq) /* change a key command to a string we can print out */
  781.  
  782. int c;          /* sequence to translate */
  783. char *seq;      /* destination string for sequence */
  784.  
  785. {
  786.         char *ptr;      /* pointer into current position in sequence */
  787.  
  788.         ptr = seq;
  789.  
  790.         /* apply ^X sequence if needed */
  791.         if (c & CTLX) {
  792.                 *ptr++ = '^';
  793.                 *ptr++ = 'X';
  794.         }
  795.  
  796.         /* apply ALT key sequence if needed */
  797.         if (c & ALTD) {
  798.                 *ptr++ = 'A';
  799.                 *ptr++ = '-';
  800.         }
  801.  
  802.         /* apply Shifted sequence if needed */
  803.         if (c & SHFT) {
  804.                 *ptr++ = 'S';
  805.                 *ptr++ = '-';
  806.         }
  807.  
  808.         /* apply MOUS sequence if needed */
  809.         if (c & MOUS) {
  810.                 *ptr++ = 'M';
  811.                 *ptr++ = 'S';
  812.         }
  813.  
  814.         /* apply meta sequence if needed */
  815.         if (c & META) {
  816.                 *ptr++ = 'M';
  817.                 *ptr++ = '-';
  818.         }
  819.  
  820.         /* apply SPEC sequence if needed */
  821.         if (c & SPEC) {
  822.                 *ptr++ = 'F';
  823.                 *ptr++ = 'N';
  824.         }
  825.  
  826.         /* apply control sequence if needed */
  827.         if (c & CTRL) {
  828.                 *ptr++ = '^';
  829.         }
  830.  
  831.         c = c & 255;    /* strip the prefixes */
  832.  
  833.         /* and output the final sequence */
  834.  
  835.         *ptr++ = c;
  836.         *ptr = 0;       /* terminate the string */
  837. }
  838.  
  839. /*      This function looks a key binding up in the binding table       */
  840.  
  841. KEYTAB *getbind(c)
  842.  
  843. int c;  /* key to find what is bound to it */
  844.  
  845. {
  846.         register KEYTAB *ktp;
  847.  
  848.         /* scan through the binding table, looking for the key's entry */
  849.         ktp = &keytab[0];
  850.         while (ktp->k_type != BINDNUL) {
  851.                 if (ktp->k_code == c)
  852.                         return(ktp);
  853.                 ++ktp;
  854.         }
  855.  
  856.         /* no such binding */
  857.         return((KEYTAB *)NULL);
  858. }
  859.  
  860. /* getfname:    This function takes a ptr to KEYTAB entry and gets the name
  861.                 associated with it
  862. */
  863.  
  864. char *PASCAL NEAR getfname(key)
  865.  
  866. KEYTAB *key;    /* key binding to return a name of */
  867.  
  868. {
  869.         int (PASCAL NEAR *func)(); /* ptr to the requested function */
  870.         register NBIND *nptr;   /* pointer into the name binding table */
  871.         register BUFFER *bp;    /* ptr to buffer to test */
  872.         register BUFFER *kbuf;  /* ptr to requested buffer */
  873.  
  874.         /* if this isn't a valid key, it has no name */
  875.         if (key == NULL)
  876.                 return(NULL);
  877.  
  878.         /* skim through the binding table, looking for a match */
  879.         if (key->k_type == BINDFNC) {
  880.                 func = key->k_ptr.fp;
  881.                 nptr = &names[0];
  882.                 while (nptr->n_func != NULL) {
  883.                         if (nptr->n_func == func)
  884.                                 return(nptr->n_name);
  885.                         ++nptr;
  886.                 }
  887.                 return(NULL);
  888.         }
  889.  
  890.         /* skim through the buffer list looking for a match */
  891.         kbuf = key->k_ptr.buf;
  892.         bp = bheadp;
  893.         while (bp) {
  894.                 if (bp == kbuf)
  895.                         return(bp->b_bname);
  896.                 bp = bp->b_bufp;
  897.         }
  898.         return(NULL);
  899. }
  900.  
  901. /* fncmatch:    match fname to a function in the names table and return
  902.                 any match or NULL if none */
  903.  
  904. int (PASCAL NEAR *PASCAL NEAR fncmatch(fname))()
  905.  
  906. char *fname;    /* name to attempt to match */
  907.  
  908. {
  909. #if     BINARY
  910.         register int nval;      /* value of matched name */
  911.  
  912.         nval = binary(fname, namval, numfunc);
  913.         if (nval == -1)
  914.                 return(NULL);
  915.         else
  916.                 return(names[nval].n_func);
  917. #else
  918.         register NBIND *ffp;    /* pointer to entry in name binding table */
  919.  
  920.         /* scan through the table, returning any match */
  921.         ffp = &names[0];
  922.         while (ffp->n_func != NULL) {
  923.                 if (strcmp(fname, ffp->n_name) == 0)
  924.                         return(ffp->n_func);
  925.                 ++ffp;
  926.         }
  927.         return(NULL);
  928. #endif
  929. }
  930.  
  931. #if     BINARY
  932. char *PASCAL NEAR namval(index)
  933.  
  934. int index;      /* index of name to fetch out of the name table */
  935.  
  936. {
  937.         return(names[index].n_name);
  938. }
  939. #endif
  940.  
  941. /*      stock()         String key name TO Command Key
  942.  
  943.         A key binding consists of one or more prefix functions followed by
  944.         a keystroke.  Allowable prefixes must be in the following order:
  945.  
  946.         ^X      preceeding control-X
  947.         A-      simeltaneous ALT key (on PCs mainly)
  948.         S-      shifted function key
  949.         MS      mouse generated keystroke
  950.         M-      Preceding META key
  951.         FN      function key
  952.         ^       control key
  953.  
  954.         Meta and ^X prefix of lower case letters are converted to upper
  955.         case.  Real control characters are automatically converted to
  956.         the ^A form.
  957. */
  958.  
  959. unsigned int PASCAL NEAR stock(keyname)
  960.  
  961. char *keyname;  /* name of key to translate to Command key form */
  962.  
  963. {
  964.         register unsigned int c;        /* key sequence to return */
  965.  
  966.         /* parse it up */
  967.         c = 0;
  968.  
  969.         /* Do ^X prefix */
  970.         if(*keyname == '^' && *(keyname+1) == 'X') {
  971.                 if(*(keyname+2) != 0) { /* Key is not bare ^X */
  972.                     c |= CTLX;
  973.                     keyname += 2;
  974.                 }
  975.         }
  976.  
  977.         /* and the ALT key prefix */
  978.         if (*keyname == 'A' && *(keyname+1) == '-') {
  979.                 c |= ALTD;
  980.                 keyname += 2;
  981.         }
  982.  
  983.         /* and the SHIFTED prefix */
  984.         if (*keyname == 'S' && *(keyname+1) == '-') {
  985.                 c |= SHFT;
  986.                 keyname += 2;
  987.         }
  988.  
  989.         /* and the mouse (MOUS) prefix */
  990.         if (*keyname == 'M' && *(keyname+1) == 'S') {
  991.                 c |= MOUS;
  992.                 keyname += 2;
  993.         }
  994.  
  995.         /* then the META prefix */
  996.         if (*keyname == 'M' && *(keyname+1) == '-') {
  997.                 c |= META;
  998.                 keyname += 2;
  999.         }
  1000.  
  1001.         /* next the function prefix */
  1002.         if (*keyname == 'F' && *(keyname+1) == 'N') {
  1003.                 c |= SPEC;
  1004.                 keyname += 2;
  1005.         }
  1006.  
  1007.         /* a control char?  (Always upper case) */
  1008.         if (*keyname == '^' && *(keyname+1) != 0) {
  1009.                 c |= CTRL;
  1010.                 ++keyname;
  1011.                 uppercase(keyname);
  1012.         }
  1013.  
  1014.         /* A literal control character? (Boo, hiss) */
  1015.         if (*keyname < 32) {
  1016.                 c |= CTRL;
  1017.                 *keyname += '@';
  1018.         }
  1019.  
  1020.         /* make sure we are not lower case if used with ^X or M- */
  1021.         if(!(c & (MOUS|SPEC|ALTD|SHFT)))        /* If not a special key */
  1022.             if( c & (CTLX|META))                /* If is a prefix */
  1023.                 uppercase(keyname);             /* Then make sure it's upper case */
  1024.  
  1025.         /* the final sequence... */
  1026.         c |= *keyname;
  1027.         return(c);
  1028. }
  1029.  
  1030. char *PASCAL NEAR transbind(skey)       /* string key name to binding name.... */
  1031.  
  1032. char *skey;     /* name of key to get binding for */
  1033.  
  1034. {
  1035.         char *bindname;
  1036.  
  1037.         bindname = getfname(getbind(stock(skey)));
  1038.         if (bindname == NULL)
  1039.                 bindname = errorm;
  1040.  
  1041.         return(bindname);
  1042. }
  1043.  
  1044. int PASCAL NEAR execkey(key, f, n)      /* execute a function bound to a key */
  1045.  
  1046. KEYTAB *key;    /* key to execute */
  1047. int f, n;       /* agruments to C function */
  1048.  
  1049. {
  1050.         register int status;    /* error return */
  1051.  
  1052.         if (key->k_type == BINDFNC)
  1053.                 return((*(key->k_ptr.fp))(f, n));
  1054.         if (key->k_type == BINDBUF) {
  1055.                 while (n--) {
  1056.                         status = dobuf(key->k_ptr.buf);
  1057.                         if (status != TRUE)
  1058.                                 return(status);
  1059.                 }
  1060.         }
  1061.         return(TRUE);
  1062. }
  1063.  
  1064. /* set a KEYTAB to the given name of the given type */
  1065.  
  1066. setkey(key, type, name)
  1067.  
  1068. KEYTAB *key;            /* ptr to key to set */
  1069. short type;             /* type of binding */
  1070. char *name;             /* name of function or buffer */
  1071.  
  1072. {
  1073.         key->k_type = type;
  1074.         if (type == BINDFNC)
  1075.                 key->k_ptr.fp = fncmatch(name);
  1076.         else if (type == BINDBUF)
  1077.                 /* not quite yet... */;
  1078. }
  1079.